﻿using System;
using System.Text.RegularExpressions;

namespace Storm.TextEditor.Editor.Interacting
{
	/// <summary>
	/// Holds information about a word.
	/// </summary>
	public class WordData
	{
		#region Fields

		private const string VJASS_FUNCTION_PATTERN = @"((?<scope>(private|public))\s+)?(?<constant>constant\s+)?func(tion)?\s(?<interface>interface\s+)?(?<name>[a-zA-Z]\w*)\s+takes\s+(?<arguments>[\w\s,]+)\sreturns\s+(?<return>\w+)";
		private const string VJASS_METHOD_PATTERN   = @"((?<scope>(private|public))\s+)?(?<static>static\s+)?(?<constant>constant\s+)?method\s+(?<name>[a-zA-Z]\w*)\s+takes\s+(?<arguments>[\w\s,]+)\sreturns\s+(?<return>\w+)";

		private const string GALAXY_PATTERN = @"";	// Not yet implemented.

		private string name        = "";
		private string description = "";
		private string declaration = "";
		private string arguments   = "";

		#endregion

		#region Properties

		/// <summary>
		/// Gets or sets the name of the Word.
		/// </summary>
		public string Name
		{
			get { return name; }
			set { name = value; }
		}

		/// <summary>
		/// Gets or sets the description of the Word.
		/// </summary>
		public string Description
		{
			get { return description; }
			set { description = value; }
		}

		/// <summary>
		/// Gets or sets the declaration of the Word.
		/// </summary>
		public string Declaration
		{
			get { return declaration; }
			set { declaration = value; }
		}

		/// <summary>
		/// Gets or sets the arguments of the Word.
		/// </summary>
		public string Arguments
		{
			get { return arguments; }
			set { arguments = value; }
		}

		#endregion

		#region Methods

		#region Public

		/// <summary>
		/// "Squishes" a string so we can get the information we want.
		/// </summary>
		/// <remarks>
		/// Instead of setting Name, Declaration and Arguments manually, you can let this method do it for you.
		///  - Uses Regular Expressions!
		/// </remarks>
		/// <param name="pattern">Language you want to find the match for, eg. vJass or Galaxy.</param>
		/// <param name="findWhat">If pattern is RegexPattern.vJass, you will need to specify whether you want to find a function or a method. For Galaxy, use RegexFind.None.</param>
		/// <param name="text">Text to be searched.</param>
		public void SquishDataFromString(RegexPattern pattern, RegexFind findWhat, string text)
		{
			// Declare our MatchCollection.
			MatchCollection matches = null;

			// Check whether the user wants a vJass or a Galaxy match
			// and set our MatchCollection to check for matches, 
			// following the defined pattern.
			if (pattern == RegexPattern.vJass)
			{
				// The pattern was vJass, we will now check what the
				// user wants us to search for.
				if (findWhat == RegexFind.Function)
					matches = Regex.Matches(text, VJASS_FUNCTION_PATTERN);
				else if (findWhat == RegexFind.Method)
					matches = Regex.Matches(text, VJASS_METHOD_PATTERN);
				else if (findWhat == RegexFind.None)
					// The user specified RegexPattern.vJass and RegexFind.None, tell him/her that he/she can't.
					throw new ArgumentNullException("findWhat can't be 'RegexFind.None' when pattern is 'RegexPattern.vJass'.");
			}
			else if (pattern == RegexPattern.Galaxy)
				matches = Regex.Matches(text, GALAXY_PATTERN);

			// Check whether we found a match, and if we did, take
			// the first found match and do magik trikz to it.
			if (matches.Count > 0)
			{
				// Squish the data out of the found match.
				name = matches[0].Groups["name"].Value;
				arguments = matches[0].Groups["arguments"].Value;
				declaration = text.Trim(); // Trim the text that the user specified 
				// so we can use it for our declaration.
			}
		}

		/// <summary>
		/// "Squishes" a string so we can get the information we want.
		/// </summary>
		/// <remarks>
		/// Instead of setting Name, Declaration and Arguments manually, you can let this method do it for you.
		/// 
		/// If you want the method to squish correctly, you will have to give the pattern a "name" and "arguments" group.
		/// Eg.: "((?<scope>(private|public))\s+)?(?<constant>constant\s+)?func(tion)?\s(?<interface>interface\s+)?(?<name>[a-zA-Z]\w*)\s+takes\s+(?<arguments>[\w\s,]+)\sreturns\s+(?<return>\w+)"
		/// </remarks>
		/// <param name="regexPattern">Regular Expression pattern to use for searching the given text.</param>
		/// <param name="text">Text to be searched.</param>
		public void SquishDataFromString(string regexPattern, string text)
		{
			// Declare our MatchCollection with the specified Regular Expression pattern.
			MatchCollection matches = Regex.Matches(text, regexPattern);

			// Check whether we found a match, and if we did, take
			// the first found match and do magik trikz to it.
			if (matches.Count > 0)
			{
				// Squish the data out of the found match.
				name = matches[0].Groups["name"].Value;
				arguments = matches[0].Groups["arguments"].Value;
				declaration = text.Trim(); // Trim the text that the user specified 
				// so we can use it for our declaration.
			}
		}

		#endregion

		#endregion

		/// <summary>
		/// Initializes a new instance of WordData.
		/// </summary>
		public WordData()
		{
		}

		/// <summary>
		/// Initializes a new instance of WordData.
		/// </summary>
		/// <param name="name">Name of the word.</param>
		/// <param name="description">Description of the word.</param>
		/// <param name="declaration">Declaration of the word.</param>
		/// <param name="arguments">Arguments of the word.</param>
		public WordData(string name, string description, string declaration, string arguments)
		{
			this.name = name;
			this.description = description;
			this.declaration = declaration;
			this.arguments = arguments;
		}
	}
}
